# -*- coding:utf-8 -*-
import os
from socket import socket, AF_INET, SOCK_STREAM, SHUT_RDWR, error as SocketError
from time import sleep


class Singleton(object):
    objs = {}

    def __new__(cls, *args, **kv):
        if cls in cls.objs:
            return cls.objs[cls]
        cls.objs[cls] = object.__new__(cls)
        return cls.objs[cls]


class AdbCore(Singleton):
    """提供核心的adb连接、通讯功能"""
    def __init__(self):
        if not hasattr(self, "__init"):
            self.__init = True
            self.__host = '127.0.0.1'
            self.__port = 5037
            self.__sn = ""
            self.__connection = None
            # self.connect()

    def get_sn(self):
        return self.__sn

    def set_sn(self, device_sn):
        self.__sn = device_sn

    def set_host_port(self, host='127.0.0.1', port=5037):
        self.__host = host
        self.__port = port

    def connect(self):
        """
        create a socket to the device, connect to it, and check it
        """
        if self.__connection is not None:
            self.close_connection()
        s = socket(AF_INET, SOCK_STREAM)
        s.connect((self.__host, self.__port))
        self.__connection = s
        # command = "host:transport-any"
        command = "host:transport:" + self.__sn
        self.write(command)
        read_data = self.read(raw=True)
        print "connect read:", read_data
        if self.status(read_data):
            return 1

    def close_connection(self):
        try:
            self.__connection.shutdown(SHUT_RDWR)
        except SocketError:
            pass  # forcibly shut down already
        self.__connection.close()
        self.__connection = None

    def write(self, command):
        # first the command needs it's length adding as a prefix
        # this is in hex form, and must be 4 digits long
        len_command = str(hex(len(command)))[2:].upper()
        while len(len_command) < 4:
            len_command = "".join(["0", len_command])
        command = "".join([len_command, command])
        self.__connection.send(command)

    def read(self, raw=False, buff=4096):
        read_data = self.__connection.recv(buff)
        if not raw:
            read_data = read_data[4:]
        return read_data

    def read_stream(self, raw=False, buff=4096):
        pass

    def receive(self, nob=None, sock=None):

        if not sock:
            sock = self.__connection
        if nob is None:
            nob = int(sock.recv(4), 16)
        recv = bytearray(nob)
        view = memoryview(recv)
        nr = 0
        while nr < nob:
            l = sock.recv_into(view, len(view))
            view = view[l:]
            nr += l
        return str(recv)

    def command(self, command, pause=0.0):
        # a new socket must be created for every command
        if not self.connect():
            return 0
        self.write(command)
        sleep(pause)
        return_data = self.read(raw=True)
        if self.status(return_data):
            return return_data[4:]
        return 0

    @staticmethod
    def status(data):
        if data[:4] == "OKAY":
            return True
        return False

    def cmd(self, command, need_result=False):
        if need_result:
            print "CMD command:", command
            return os.popen(command)
        else:
            print "CMD command:", command
            return os.system(command)

if __name__ == '__main__':
    adb = AdbCore("4c1b15e5")
    # adb.connect()
    abc = adb.command("shell ls")
    print abc
